package com.qf.ability.gateway.filter;

import com.qf.ability.gateway.config.AuthParamConfig;
import com.qf.ability.gateway.util.ResponseUtils;
import com.qf.commons.core.utils.JwtUtils;
import com.qf.data.base.r.Codes;
import com.qf.data.base.r.R;
import com.qf.data.base.r.Rs;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.util.List;

/**
 * 全局过滤器
 *
 * @RefreshScope - 当配置中心上有配置改变时，该注解标记的类 会被重新注入
 *
 * description: 身份校验的过滤器，判断当前请求是否登录
 * author: Ken
 * 公众号：Java架构栈
 */
@Component
@Slf4j
@RefreshScope
public class AuthFilter implements GlobalFilter, Ordered {



    /**
     * 获取需要忽略的请求地址
     */
    @Autowired
    private AuthParamConfig authParamConfig;

    private AntPathMatcher antPathMatcher = new AntPathMatcher();

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("[gateway auth filter] - 用户身份校验的过滤器！");


        //判断当前请求是否需要忽略
        URI url = exchange.getRequest().getURI();
        log.info("[gateway auth filter] - 请求的url:{} 忽略的url:{}", url.getPath(), authParamConfig.getIgnore());
        //获取需要忽略的请求地址列表
        List<String> ignore = authParamConfig.getIgnore();
        if (!CollectionUtils.isEmpty(ignore)) {
            for (String ignorePath : ignore) {
                if (antPathMatcher.match(ignorePath, url.getPath())) {
                    //需要忽略，直接放行
                    return chain.filter(exchange);
                }
            }
        }

        //1、获取请求的token
        ServerHttpRequest request = exchange.getRequest();
        HttpHeaders headers = request.getHeaders();
        String jwtToken = headers.getFirst("token");
        log.info("[gateway auth filter] - 获取请求的令牌 - {}", jwtToken);

        //判断令牌是否为空
        if (StringUtils.isEmpty(jwtToken)) {
            R result = Rs.createFail(Codes.NOT_LOGIN);
            return ResponseUtils.createResponse(result, exchange, HttpStatus.BAD_REQUEST);
        }

        //令牌不为空，身份解析
        Long uid = JwtUtils.parseJwtToken(jwtToken);
        if (uid == null) {
            R result = Rs.createFail(Codes.TOKEN_EXPRES);
            return ResponseUtils.createResponse(result, exchange, HttpStatus.BAD_REQUEST);
        }

        //身份id不为空，需要传递给后续的微服务，将身份id直接放入请求的请求头/请求参数中
        //创建一个新的请求头
        HttpHeaders newHeader = new HttpHeaders();
        newHeader.putAll(headers);//将原来的请求头数据放入新的请求头
        newHeader.add("uid", uid + ""); //将登陆的用户信息 放入新的请求头中

        //准备一个新的请求
        URI uri = request.getURI();//旧请求的url地址
        ServerHttpRequest newRequest = request.mutate().uri(uri).build();
        newRequest = new ServerHttpRequestDecorator(newRequest) {
            @Override
            public HttpHeaders getHeaders() {
                return newHeader;
            }
        };

        //放行
        return chain.filter(exchange.mutate().request(newRequest).build());
    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE + 100;
    }
}
